package com.cskaoyan.javase.oop2._1extends._7initialization._0introduction;

/**
 * 为了讲解子类对象的初始化问题,给出一个引例
 * 我们通过一个引例，练习来讲解这个问题：
 * 创建一个Person类，有name属性和eat方法
 * 创建一个Star类，有stageName属性和sing方法
 * Star类要继承Person类
 * 创建Star类对象，画出这个过程的内存图，描述子类对象初始化的过程。
 *
 * 结论/总结:
 *      1.创建对象,触发类加载,这个类加载是"先父后子"的.
 *          而且如果类的继承层次有多级,应该从顶层父类开始向下完成类加载
 *          补充:
 *              触发子类类加载,会不会先触发父类的类加载
 *              会,这也是一种类加载的时机
 *
 *              某个类如果存在父类,触发它的类加载,优先类加载它的父类
 *      2.类加载结束后,开始创建对象,注意这时仅会创建一个子类对象,绝不会创建父类对象!!
 *      3.创建对象后,在子类对象中,会开辟一片区域专门用来存放父类成员
 *          这片区域可以近似的看成一个父类对象(不是对象,只是近似看成)
 *          使用关键字super指向它
 *
 * 现在我们知道,父类成员和子类自身成员在子类对象中会存储在不同的区域,那么最关键的问题来了:
 *      父子类的成员变量,它们如何赋值,赋值的顺序是什么?赋值的结果是什么?
 *      1.不管什么赋值手段,首先的第一步都是默认初始化具有默认值,这个过程不考虑先后顺序
 *          只要对象创建出来,成员变量统统具有默认值.
 *      2.除开默认值,还有:
 *          a.显式赋值
 *          b.构造代码块赋值
 *          c.构造器赋值
 *      那些这些赋值方式,先后顺序是什么样的呢?(在继承中)
 *      从逻辑角度考虑,应该是"先父后子"的
 *      实际上通过代码测试,赋值顺序确实是"先父后子"的
 *
 *
 * 父子类成员变量的赋值顺序的"先父后子"，是怎么保证的呢？
 * 为什么能够体现出这种特点呢？接下来，我们详细分析一下子类对象中，父子类成员变量的赋值顺序。
 *
 * 思考:
 *      如果想要保证父类的赋值手段都在子类成员的赋值手段之前进行,只要保证什么?
 *      只要保证父类成员的赋值手段中最后一个执行的 要在 子类成员的赋值手段中最先执行的 之前
 *      谁是最后一个执行的赋值手段?
 *      构造器
 *      所以只需要保证父类的构造器在子类的构造器之前运行即可!
 *
 *      创建子类对象,父类构造器会不会执行?
 *      我们发现创建子类对象,父类的构造代码块会执行,所以父类构造器也执行了.
 *
 *      所以我们猜想是可行的,只要保证父类构造器先于子类构造器执行,那么父类的所有赋值手段都在子类之前执行!!
 *
 * 创建子类对象过程中,构造器的执行也是从顶层父类开始的
 * 肯定是从Object类开始的,但是Object类无参构造对代码输出执行没有影响
 *
 *  问题:
 *      父类的构造器如何先于子类构造器执行?
 *          this(实参列表) 表示调用自身的其他构造器
 *          super指向父类成员的那片区域,可以近似的看成一个父类对象
 *          那么在子类的构造器中,就可以用super(实参列表)表示调用父类的构造器
 *          实际上这样就引出了子类对象初始化的两种方式
 *  1.子类对象的隐式初始化
 *      在一个类的构造器中,如果这个构造器的第一行代码没有显式的使用this或者super去调用其他构造器
 *          那么它的第一行会隐含一句:
 *          super();
 *          表示调用父类的无参构造器
 *
 *          这种通过隐含super()
 *          去实现成员赋值的先父后子的
 *          创建子类对象的方式
 *          称之为"子类对象的隐式初始化"
 *
 * 2.子类对象的隐式初始化无法完成子类对象中父类成员的赋值,如果想要赋值,那就需要明确调用父类的有参构造器
 * 称之为"子类对象的显式初始化"
 * 语法:
 *      super(实参列表);
 * 子类对象的显式初始化,需要明确调用父类的哪个构造器
 *
 * @since 15:59
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo2 {
    public static void main(String[] args) {
        // Star s = new Star();
        // System.out.println(s.stageName);
        Star s = new Star("马化腾");
        System.out.println(s.name);

    }
}

class Person {
    // static {
    //     System.out.println("Person类类加载");
    // }
    String name = "张三";

    {
        System.out.println("Person类构造代码块");
    }

    public void eat() {
        System.out.println("吃饭多是一件美事!");
    }

    public Person() {
        // 隐含super(); 指向Object类的无参构造器
    }

    public Person(String name) {
        this.name = name;
    }
}

class Star extends Person {
    // static {
    //     System.out.println("Star类类加载");
    // }
    // 艺名
    String stageName = name + "的弟弟";

    {
        System.out.println("Star类构造代码块");
    }


    public void sing() {
        System.out.println("唱一首爱的供养!");
    }

    public Star() {
        // 隐含super();
        // super();
    }

    public Star(String name) {
        super(name);
    }
}